﻿using APP.BaseClass;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace APP.OpenCV
{
    public class OpenCVHelper
    {


        public static void TestBoard(string imagePath)
        {

            Mat image = Cv2.ImRead(imagePath);
            Mat gray = new Mat();
            //# 转换为灰度图
            Cv2.CvtColor(image, gray, ColorConversionCodes.RGB2GRAY);

            Mat binary = new Mat();
            //# 转为二值图
            Cv2.Threshold(gray, binary, 60, 255, ThresholdTypes.Binary);
            //ret, binary =
            //# 膨胀算法的色块大小

            var hors_k = (int)(Math.Sqrt(binary.Width) * 1.2);
            var vert_k = (int)(Math.Sqrt(binary.Height) * 1.2);

            //# 白底黑字，膨胀白色横向色块，抹去文字和竖线，保留横线
            Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(hors_k, 1));
            Mat hors = new Mat();
            Cv2.Dilate(binary, hors, kernel, iterations: 1);//# 迭代两次，尽量抹去文本横线，变反为黑底白线

            //# 白底黑字，膨胀白色竖向色块，抹去文字和横线，保留竖线
            kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(1, vert_k));
            Mat verts = new Mat();
            Cv2.Dilate(binary, verts, kernel, iterations: 1); //# 迭代两次，尽量抹去文本竖线，变反为黑底白线

            //# 横线竖线检测结果合并
            Mat borders = new Mat();
            Cv2.BitwiseOr(hors, verts, borders);

            Cv2.ImShow("ttt", borders);
            Cv2.WaitKey();
        }



        public static void GetImageColorRange(string imagePath, out Color minHSV, out Color maxHSV, out Color minRGB, out Color maxRGB, out Color meanC, out Color stddveC)
        {
            var imageMat = Cv2.ImRead(imagePath);
            imageMat.GetRGBFromArea(out Vec3b minRGB_vec, out Vec3b maxRGB_vec);
            minRGB = RGBToColor(minRGB_vec);
            maxRGB = RGBToColor(maxRGB_vec);

            Cv2.MeanStdDev(imageMat, out Scalar mean, out Scalar stddev);
            meanC = MeanToColor(mean);
            stddveC = MeanToColor(stddev);
            imageMat.GetHSVFromArea(out Vec3b minHSV_vec, out Vec3b maxHSV_vec, out Scalar hsvmean);
            minHSV = HsvColor(minHSV_vec);
            maxHSV = HsvColor(maxHSV_vec);

            stddveC = MeanToColor(hsvmean);


        }
        public static System.Drawing.Color MeanToColor(Scalar rgb)
        {
            return Color.FromArgb((int)rgb.Val0, (int)rgb.Val1, (int)rgb.Val2, (int)rgb.Val3);
        }

        public static Vec3b HsvTorgb2(Vec3b hsv)
        {
            Mat hsvMat = new Mat(1, 1, MatType.CV_8UC3, new Scalar(hsv.Item0, hsv.Item1, hsv.Item2));
            Mat rgbMat = new Mat();
            Cv2.CvtColor(hsvMat, rgbMat, ColorConversionCodes.HSV2RGB);
            Vec3b vec_imgSrc1 = rgbMat.Get<Vec3b>(0, 0);
            rgbMat.Dispose();
            hsvMat.Dispose();
            return vec_imgSrc1;
        }
        public static System.Drawing.Color RGBToColor(Vec3b rgb)
        {
            return Color.FromArgb(rgb.Item0, rgb.Item1, rgb.Item2);
        }
        public static System.Drawing.Color HsvColor(Vec3b hsv)
        {
            var rgb = HsvTorgb2(hsv);
            return Color.FromArgb(rgb.Item0, rgb.Item1, rgb.Item2);
        }

        public static Bitmap MatToBitmap(Mat dst)
        {
            return new Bitmap(dst.Cols, dst.Rows, (int)dst.Step(), PixelFormat.Format24bppRgb, dst.Data);
        }

        public static Mat BitmapToMat(Bitmap srcbit)
        {
            int iwidth = srcbit.Width;
            int iheight = srcbit.Height;
            int iByte = iwidth * iheight * 3;
            byte[] result = new byte[iByte];
            int step;
            Rectangle rect = new Rectangle(0, 0, iwidth, iheight);
            BitmapData bmpData = srcbit.LockBits(rect, ImageLockMode.ReadWrite, srcbit.PixelFormat);
            IntPtr iPtr = bmpData.Scan0;
            Marshal.Copy(iPtr, result, 0, iByte);
            step = bmpData.Stride;
            srcbit.UnlockBits(bmpData);
            return new Mat(srcbit.Height, srcbit.Width, new MatType(MatType.CV_8UC3), result, step);
        }

        public static FeedBack<System.Windows.Rect> MinAreaRectAndImg(Mat src, Vec3b mincolor, Vec3b maxcolor)
        {

            FeedBack<System.Windows.Rect> result = new FeedBack<System.Windows.Rect>();
            result.Success = false;
            Mat img_hsv = new Mat();
            Cv2.CvtColor(src, img_hsv, ColorConversionCodes.BGR2HSV);
            Mat outImg = new Mat();
            var minHsv = new Scalar(mincolor.Item0, mincolor.Item1, mincolor.Item2);
            var maxHsv = new Scalar(maxcolor.Item0 + 1, maxcolor.Item1, maxcolor.Item2);
            Cv2.InRange(img_hsv, minHsv, maxHsv, outImg);
            //Cv2.ImShow("12312", outImg);

            //透明图像
            //OpenCvSharp. Vector<int> compression_params;
            // compression_params.push_back(IMWRITE_PNG_COMPRESSION);
            // compression_params.push_back(9); // 最佳质量


            Mat outhierarchy = new Mat();
            Cv2.FindContours(outImg, out Mat[] coutours, outhierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxNone);
            var list = coutours.Select(x => Cv2.BoundingRect(x));

            var min_x = list.Min(x => x.Left);
            var min_y = list.Min(x => x.Top);

            var max_x = list.Max(x => x.Right);
            var max_y = list.Max(x => x.Bottom);
            var winrect = new System.Windows.Rect(min_x, min_y, Math.Abs(max_x - min_x), Math.Abs(max_y - min_y));
            result.Data = winrect;

            //var outImage2 = img_hsv.Clone();

            var outImage2 = new Mat(img_hsv.Rows, img_hsv.Cols, MatType.CV_8UC3);
            Mat invertMask = new Mat();
            Cv2.BitwiseNot(outImg, invertMask);
            //Cv2.ImShow("invertMask", invertMask);
            img_hsv.CopyTo(outImage2, invertMask);
            Cv2.CvtColor(outImage2, outImage2, ColorConversionCodes.HSV2BGR);
            //Cv2.ImShow("img_hsv1", img_hsv);
            //Cv2.ImShow("invertMask1", invertMask);
            //Cv2.ImShow("outImage21", outImage2);

            Mat colorMask = new Mat(outImg.Height, outImg.Width, MatType.CV_8UC3, new Scalar(0, 0, 255));
            Mat colorMasked = new Mat(outImg.Height, outImg.Width, MatType.CV_8UC3);
            colorMask.CopyTo(colorMasked, outImg);
            //Cv2.ImShow("colorMasked", colorMasked);
            Cv2.BitwiseOr(outImage2, colorMasked, outImage2);
            //Cv2.ImShow("outImage2-2", outImage2);


            ImageEncodingParam imageEncoding1 = new ImageEncodingParam(ImwriteFlags.PngCompression, 0);
            string tempPath = System.IO.Path.GetTempFileName();
            tempPath = System.IO.Path.ChangeExtension(tempPath, ".png");
            Cv2.ImWrite(tempPath, outImage2, imageEncoding1);
            result.Message = tempPath;


            return result;
        }

        public static System.Windows.Rect MinAreaRect(Mat src, Vec3b mincolor, Vec3b maxcolor)
        {
            Mat img_hsv = new Mat();
            Cv2.CvtColor(src, img_hsv, ColorConversionCodes.BGR2HSV);
            Mat outImg = new Mat();
            var minHsv = new Scalar(mincolor.Item0, mincolor.Item1, mincolor.Item2);
            var maxHsv = new Scalar(maxcolor.Item0 + 1, maxcolor.Item1, maxcolor.Item2);
            Cv2.InRange(img_hsv, minHsv, maxHsv, outImg);
            //Cv2.ImShow("12312", outImg);
            Mat outhierarchy = new Mat();
            Cv2.FindContours(outImg, out Mat[] coutours, outhierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxNone);
            var list = coutours.Select(x => Cv2.BoundingRect(x));

            var min_x = list.Min(x => x.Left);
            var min_y = list.Min(x => x.Top);

            var max_x = list.Max(x => x.Right);
            var max_y = list.Max(x => x.Bottom);
            var winrect = new System.Windows.Rect(min_x, min_y, Math.Abs(max_x - min_x), Math.Abs(max_y - min_y));
            return winrect;
        }
    }
}
